Creating an Interface for data binding in Views with WPF
Perhaps you have seen the same idea as me. A list of bound objects and an interface with a list of properties, have a lot in common. To start with, both are contracts. By adding Bindings in WPF, you are creating a contract that promises any code that uses the view that if such code has certain properties to bind to, the view will bind to them. Similarly an interface is a contract wherein an object that implements the interface is required to comply with the interface else a build error.
Look at the following UserControl view.
<UserControl x:Class="BindingsAsInterfaceExample.View.PeopleView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="200" d:DesignWidth="300" > <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <DataGrid ItemsSource="{Binding People}" Grid.Row="0" Grid.ColumnSpan="3" HeadersVisibility="Column" CanUserAddRows="False" /> <Button Content="Add Person" Command="{Binding AddPersonCommand}" Grid.Row="1" Grid.Column="0" /> <Button Content="Edit Person" Command="{Binding EditPersonCommand}" Grid.Row="1" Grid.Column="1" /> <Button Content="Delete Person" Command="{Binding DeletePersonCommand}" Grid.Row="1" Grid.Column="2" /> </Grid> </UserControl>
There are four bindings in this view. It may be beneficial to make these bindings into a concrete contract using an interface.
public interface IPeopleViewBindings { IList People { get; set; } ICommand AddPersonCommand { get; set; } ICommand EditPersonCommand { get; set; } ICommand DeletePersonCommand { get; set; } }
Then when implementing the view model, have it implement the interface. Now if some binding value is missing, a compile time error occurs.
using System.Collections; using System.Collections.Generic; using System.Windows.Input; using BindingsAsInterfaceExample.Interfaces; using BindingsAsInterfaceExample.Model; using MVVM; namespace BindingsAsInterfaceExample.ViewModel { class PeopleViewModel : ViewModelBase, IPeopleViewBindings { #region Properties public IList People { get { return _People ?? (_People = CreateSamplePeople()); } set { _People = value; } } private IList _People; public ICommand AddPersonCommand { get { return _AddPersonCommand ?? (_AddPersonCommand = new RelayCommand(f => AddPerson(), f => AddPersonCanExecute())); } set { _AddPersonCommand = value; } } private ICommand _AddPersonCommand; public ICommand EditPersonCommand { get { return _EditPersonCommand ?? (_EditPersonCommand = new RelayCommand(f => EditPerson(), f => EditPersonCanExecute())); } set { _EditPersonCommand = value; } } private ICommand _EditPersonCommand; public ICommand DeletePersonCommand { get { return _DeletePersonCommand ?? (_DeletePersonCommand = new RelayCommand(f => DeletePerson(), f => DeletePersonCanExecute())); } set { _DeletePersonCommand = value; } } private ICommand _DeletePersonCommand; #endregion #region Functions private IList CreateSamplePeople() { IList people = new List<Person>(); people.Add(new Person() { FirstName = "John", MiddleName = "J.", LastName = "Johnson" }); people.Add(new Person() { FirstName = "Mark", MiddleName = "M.", LastName = "Markson" }); people.Add(new Person() { FirstName = "Thom", MiddleName = "T.", LastName = "Thompson" }); return people; } private void AddPerson() { // ... } private bool AddPersonCanExecute() { return true; } private void EditPerson() { // ... } private bool EditPersonCanExecute() { return true; } private void DeletePerson() { // ... } private bool DeletePersonCanExecute() { return true; } #endregion } }
This is solution is not without problems.
- Now when you add a binding to a view, you have to remember to add it to the interface as well, otherwise you are no better off.
- Interfaces don’t support private fields and a lot of the methods are private.
However, it is actually quite useful when creating an API that someone else is consuming. Users of the API documentation will be grateful for the interfaces.
Glad to have found this. I have had the same idea, and it’s good to see that someone agrees with me :-). I’ve been adding an interface to all my WPF items for a while now, and it does seem to work well. To add to what’s here, I’ve also found that adding an interface for the items in a DataGrid is helpful.
[…] LearningIn between code and designWPF ControlsWPF self-training course for designersWPF self-training course for developersC#WPF Interview QuestionsMembersMVVMWPFPostsContactAdvertise « Creating an Interface for data binding in Views with WPF […]